using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SynoManager.GUI;
using System.IO;
using System.Diagnostics;

namespace SynoManager.DownloadStation
{
    [ToolboxItem(false)]
    public partial class DownloadGuiTab : UserControl
    {
        private readonly DownloadGuiPlugin plugin;
        private readonly DownloadStationService service;
        private readonly ListViewItemSorter sorter = new ListViewItemSorter();

        public DownloadGuiTab()
        {
            InitializeComponent();
            splitContainer1.Panel2Collapsed = true;
            Text = "Downloads";
            taskListView.ListViewItemSorter = sorter;
        }

        public DownloadGuiTab(DownloadGuiPlugin plugin)
            :this()
        {
            this.plugin = plugin;
            this.service = plugin.service;
            service.TaskAdded += new DownloadTaskEventHandler(service_TaskAdded);
            service.TaskRemoved += new DownloadTaskEventHandler(service_TaskRemoved);
            service.TasksUpdated += new EventHandler(service_TaskUpdated);
            BuildList();
        }

        private void BuildList()
        {
            taskDict = new Dictionary<DownloadTask, ListViewItem>();
            taskListView.Items.Clear();
            service.Refresh();
            foreach (DownloadTask task in service.Tasks)
            {
                AddTask(task);
            }
        }

        private Dictionary<DownloadTask, ListViewItem> taskDict;
        private void AddTask(DownloadTask task)
        {
            if (taskDict.ContainsKey(task))
            {
                //    
                return;
            }

            //ListViewItem setup
            ListViewItem lvi = taskListView.Items.Add(task.Filename);
            lvi.SubItems.Add(task.State.ToString());
            lvi.SubItems.Add(task.Progress.ToString("0.0%"));
            lvi.SubItems.Add(task.Progress.ToString("0.0%"));
            lvi.SubItems.Add(task.RateCurrent.ToByteString());
            lvi.SubItems.Add(task.RateUpload.ToByteString());
            lvi.SubItems.Add(task.PeersConnected + "/" + task.PeersTotal);
            lvi.SubItems.Add(task.Username);
            lvi.SubItems.Add(task.SizeCurrent.ToString());
            lvi.SubItems.Add(task.SizeTotal.ToString());
            lvi.SubItems.Add(task.RemainingEstimate.ToString());

            // (Vistastyle) Progressbar
            VistaProgressBar bar = new VistaProgressBar();
            bar.Value = (int)(task.Progress * 100);
            bar.State = GetProgressState(task);
            taskListView.AddEmbeddedControl(bar, 2, lvi.Index);

            lvi.Tag = new DownloadListItemTag(task, bar);

            taskDict.Add(task, lvi);

            task.Updated += new DownloadTaskEventHandler(task_Updated);
        }

        void task_Updated(object sender, DownloadTaskEventArgs e)
        {
            DownloadTask task = e.Task;
            ListViewItem lvi = taskDict[task];
            lvi.SubItems[0].Text = task.Filename;
            lvi.SubItems[1].Text = task.State.ToString();
            lvi.SubItems[2].Text = task.Progress.ToString("0.0%");
            lvi.SubItems[3].Text = task.Progress.ToString("0.0%");
            lvi.SubItems[4].Text = task.RateCurrent.ToByteString();
            lvi.SubItems[5].Text = task.RateUpload.ToByteString();
            lvi.SubItems[6].Text = task.PeersConnected + "/" + task.PeersTotal;
            lvi.SubItems[7].Text = task.Username;
            lvi.SubItems[8].Text = task.SizeCurrent.ToString();
            lvi.SubItems[9].Text = task.SizeTotal.ToString();
            lvi.SubItems[10].Text = task.RemainingEstimate.ToString();

            var tag = (DownloadListItemTag) lvi.Tag;
            var bar = tag.ProgressBar;
            bar.Value = (int)(task.Progress * 100);
            bar.State = GetProgressState(task);

            UpdateInfoPanel();
            plugin.updateToolStrip();
        }

        void service_TaskUpdated(object sender, EventArgs e)
        {
            plugin.updateTotals();
        }

        public static ProgressBarState GetProgressState(DownloadTask task)
        {
            if ((int)task.State >= 100)
                return ProgressBarState.Error;
            if (task.State == DownloadState.Paused)
                return ProgressBarState.Paused;

            return ProgressBarState.Normal;
        }

        private void DownloadGuiTab_Load(object sender, EventArgs e)
        {
            UpdateInfoPanel();
            plugin.updateToolStrip();
        }

        private void taskListView_SelectedIndexChanged(object sender, EventArgs e)
        {
            UpdateInfoPanel();
            plugin.updateToolStrip();
        }

        public int SelectedItemsCount
        {
            get { return taskListView.SelectedItems.Count; }
        }

        public bool AllowProperties
        {
            get {
                return SelectedItemsCount == 1; 
            }
        }

        public bool AllowPause
        {
            get
            {
                if (SelectedItemsCount == 0)
                    return false;

                // Find a task that is currently in the state of downloading...
                foreach(ListViewItem lvi in taskListView.SelectedItems)
                {
                    var tag = (DownloadListItemTag)lvi.Tag;
                    if ((tag.Task.State == DownloadState.Downloading) || (tag.Task.State == DownloadState.Seeding))
                        return true; 
                }

                return false;
            }
        }

        public bool AllowResume
        {
            get
            {
                if (SelectedItemsCount == 0)
                    return false;

                // Find a task that is currently in a paused state...
                foreach (ListViewItem lvi in taskListView.SelectedItems)
                {
                    var tag = (DownloadListItemTag)lvi.Tag;
                    if ((tag.Task.State == DownloadState.Paused) || (tag.Task.State >= DownloadState.Error))
                        return true;
                }

                return false;
            }
        }

        public bool AllowOpen
        {
            get
            {
                if (SelectedItemsCount != 1)
                    return false;

                var task = ((DownloadListItemTag) taskListView.SelectedItems[0].Tag).Task;
                if (task.State != DownloadState.Completed)
                    return false;

                return true;
            }
        }

        #region Service Events
        void service_TaskRemoved(object sender, DownloadTaskEventArgs e)
        {
            if (taskDict.ContainsKey(e.Task))
            {
                taskListView.Items.Remove(taskDict[e.Task]);
                taskDict.Remove(e.Task);
            }
        }

        void service_TaskAdded(object sender, DownloadTaskEventArgs e)
        {
            AddTask(e.Task);
        }
        #endregion

        internal struct DownloadListItemTag
        {
            private readonly DownloadTask task;
            private readonly VistaProgressBar progressBar;

            public DownloadListItemTag(DownloadTask task, VistaProgressBar progressBar)
            {
                this.task = task;
                this.progressBar = progressBar;
            }

            public VistaProgressBar ProgressBar
            {
                get { return progressBar; }
            }

            public DownloadTask Task
            {
                get { return task; }
            }
        }

        public void ResumeSelected()
        {
            foreach(ListViewItem lvi in taskListView.SelectedItems)
            {
                var tag = (DownloadListItemTag) lvi.Tag;
                tag.Task.Resume();
            }
        }

        public void PauseSelected()
        {
            foreach (ListViewItem lvi in taskListView.SelectedItems)
            {
                var tag = (DownloadListItemTag)lvi.Tag;
                tag.Task.Pause();
            }
        }

        public void RemoveSelected()
        {
            var tasks = new List<DownloadTask>();
            bool confirm = false;
            foreach (ListViewItem lvi in taskListView.SelectedItems)
            {
                var tag = (DownloadListItemTag)lvi.Tag;
                tasks.Add(tag.Task);

                if (tag.Task.State != DownloadState.Completed)
                    confirm = true;
            }

            if (confirm)
            {
                if (DialogResult.No == MessageBox.Show(this, "Are you sure you wish to stop and remove the selected task(s)", "Remove tasks", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2))
                    return;
            }

            foreach(DownloadTask task in tasks)
                task.Remove();
        }

        public void ShowProperties()
        {
            if (taskListView.SelectedItems.Count != 1)
                return;

            DownloadListItemTag tag = (DownloadListItemTag) taskListView.SelectedItems[0].Tag;
            DownloadTask task = tag.Task;
            
            DownloadTaskPropertiesForm form = new DownloadTaskPropertiesForm(task);
            form.ShowDialog();
        }

        #region Context Menu
        private void listViewContextMenuStrip_Opening(object sender, CancelEventArgs e)
        {
            if (taskListView.SelectedItems.Count == 0)
            {
                e.Cancel = true;
                return;
            }

            pauseToolStripMenuItem.Enabled = AllowPause;
            resumeToolStripMenuItem.Enabled = AllowResume;
            propertiesToolStripMenuItem.Enabled = AllowProperties;
            openFileToolStripMenuItem.Enabled = AllowOpen;
        }

        private void pauseToolStripMenuItem_Click(object sender, EventArgs e)
        {
            PauseSelected();
        }

        private void resumeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ResumeSelected();
        }

        private void propertiesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ShowProperties();
        }

        private void openFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var tag = (DownloadListItemTag) taskListView.SelectedItems[0].Tag;
            var task = tag.Task;
            try
            {
                task.OpenFile();
            }
            catch (FileNotFoundException ex)
            {
                MessageBox.Show(this.FindForm(), ex.Message, "Open Task", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void removeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            RemoveSelected();
        }
        #endregion


        #region InfoPanel
        private void UpdateInfoPanel()
        {
            splitContainer1.Panel2Collapsed = (taskListView.SelectedItems.Count != 1);

            if (splitContainer1.Panel2Collapsed)
                return; // ignore, we're not visible

            DownloadTask task = ((DownloadListItemTag) taskListView.SelectedItems[0].Tag).Task;
            fileNameLabel.Text = task.Filename;
            urlLabel.Text = task.Url;
            peersLabel.Text = task.PeersConnected + "/" + task.PeersTotal;
            piecesLabel.Text = String.Format("{0}/{1}/{2} (Downloaded/Available/Total)", task.PiecesDownloaded,
                                             task.PiecesAvailable, task.PiecesTotal);
            statusLabel.Text = task.State.ToString();
            progressLabel.Text = String.Format("{0:0.##}%", task.Progress * 100);
            progressBar.Value = (int) (task.Progress * 100);
            progressBar.State = GetProgressState(task);
            sizeLabel.Text = String.Format("{0} / {1}", task.SizeCurrent, task.SizeTotal);
            speedLabel.Text = String.Format("{0}/s down / {1}/s up", task.RateCurrent.ToByteString(), task.RateUpload.ToByteString());
            etaLabel.Text = task.RemainingEstimate.ToString();
        }
        #endregion

        internal void Save()
        {
            Properties.Settings.Default.FileColumnWidth = fileColumn.Width;
            Properties.Settings.Default.StatusColumnWidth = statusColumn.Width;
            Properties.Settings.Default.ProgressColumnWidth = progressColumn.Width;
            Properties.Settings.Default.ProgressPercentColumnWidth = progressPercentColumn.Width;
            Properties.Settings.Default.SpeedDownColumnWidth = speedDownColumn.Width;
            Properties.Settings.Default.SpeedUpColumnWidth = speedUpColumn.Width;
            Properties.Settings.Default.PeersColumnWidth = peersColumn.Width;
            Properties.Settings.Default.UserColumnWidth = userColumn.Width;
            Properties.Settings.Default.SizeCurrentWidth = sizeCurrentColumn.Width;
            Properties.Settings.Default.SizeTotalWidth = sizeTotalColumn.Width;
            Properties.Settings.Default.EtaColumnWidth = etaColumn.Width;
        }

        private void taskListView_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            if (sorter.Column == (ListViewItemSorter.SortColumn)e.Column)
            {
                sorter.Descending = !sorter.Descending;
            }
            else
            {
                sorter.Column = (ListViewItemSorter.SortColumn) e.Column;
                sorter.Descending = false;
            }

            taskListView.Sort();
        }

        private void taskListView_DoubleClick(object sender, EventArgs e)
        {
            if (AllowProperties)
                ShowProperties();
        }
    }
}
